package artibella.media.video 
{
	import artibella.media.AList;
	import artibella.media.AListItem;
	import artibella.media.APlayer;
	import artibella.media.ControllerMode;
	import artibella.media.controls.AController;
	import artibella.media.controls.ui.PlayButton;
	import artibella.media.controls.VideoController;
	import artibella.media.DisplayMode;
	import artibella.media.events.InfoEvent;
	import artibella.media.events.MediaEvent;
	import artibella.media.LoopMode;
	import artibella.media.video.VideoConnector;
	import artibella.media.video.VideoConnectorParameters;
	import artibella.media.video.VideoMedia;
	import artibella.media.video.VideoMediaParameters;
	import artibella.StageManager;
	
	import caurina.transitions.properties.DisplayShortcuts;
	import caurina.transitions.Tweener;
	
	import flash.display.MovieClip;
	import flash.display.StageDisplayState;
	import flash.events.MouseEvent;
	import flash.events.TimerEvent;
	import flash.geom.Rectangle;
	import flash.utils.Timer;
	
	/**
	 * ...
	 * @author pbordachar
	 */
	
	public class VideoPlayer extends APlayer
	{
		private var _currentMedia:VideoMedia;
		
		private var _connection:VideoConnector;
		private var _display:VideoDisplay;
		
		private var _bt_play_big:MovieClip;
		
		private var _loopMode:String;
		private var _autoPlay:Boolean;
		
		private var _controllerMode:String;
		private var _t:Timer;
		
		private var _previewURL:String;
		

		public function VideoPlayer( w:int = 0, h:int = 0, bgColor:int = 0x333333, dm:String = DisplayMode.FIT )
		{
			super();
			
			_controllerMode = ControllerMode.ALWAYS;
			_loopMode = LoopMode.LIST;
			
			DisplayShortcuts.init();

			StageManager.instance.addObserver( this );
			
			if( w != 0 && h != 0 ){
				setDisplay( w, h, bgColor, dm );
			}
		}
		
		// - - -
		
		public function connect( autoplay:Boolean = false ):void 
		{
			_autoPlay = autoplay;
			
			if ( !_autoPlay ) setPlayButtonBig( new PlayButton( 0xFFFFFF ) );
			
			var parameters:VideoConnectorParameters = new VideoConnectorParameters();
			parameters.onStreamReady = _onStreamReady;
			
			_connection = new VideoConnector( parameters );
			_connection.addEventListener( MediaEvent.PLAY_COMPLETE, _onComplete );
			_connection.init();
		}
		
		private function _onStreamReady():void
		{	
			if( _display != null ) _display.screen.attachNetStream( _connection.netStream );
			
			play();
		}
		
		public function _onComplete( e:MediaEvent ):void
		{
			switch( _loopMode ) {
				
				case LoopMode.NONE : 
					
					_currentMedia.seek( 0, true );
					
					if ( _display.hasPreview ) {
						_display.screen.visible = false;
					} else {
						_currentMedia.seek( 0, true );
					}
					
					if ( _bt_play_big != null ) _bt_play_big.visible = true;
					
					break;
					
				case LoopMode.ITEM : 
				
					_currentMedia.seek( 0, false );
					
					break;
					
				case LoopMode.LIST : 
				
					next();
			}
		}
		
		// - - -

		public function setDisplay( w:int, h:int, bgColor:int = 0x333333, dm:String = DisplayMode.FIT ):void
		{
			if ( _display != null ) return;
			
			scrollRect = new Rectangle( 0, 0, w, h );
			
			_display = new VideoDisplay( w, h, bgColor, dm );
			_view.addChildAt( _display, 0 );
			
			_relocate();
			
			if( _previewURL != null ) _display.loadPreview( _previewURL );
		}
		
		public function loadPreview( u:String ):void
		{
			if ( _display != null ) 
			{
				_display.loadPreview( u );
			} 
			else 
			{
				_previewURL = u;
			}
		}
		
		public function setPlayButtonBig( mc:MovieClip ):void
		{
			if ( _bt_play_big != null || _display == null ) return;
			
			_bt_play_big = mc;
			_bt_play_big.x = _display.baseWidth / 2;
			_bt_play_big.y = _display.baseHeight / 2;
			
			_bt_play_big.addEventListener( MouseEvent.CLICK, _doPlay );
			
			_view.addChild( _bt_play_big );
		}
		
		private function _doPlay( e:MouseEvent ):void
		{
			if( _controller != null ) _controller.setPlayState();
		}
		
		// - - -
		
		override public function set controller( c:AController ):void
		{
			_controller = ( c != null ) ? c : new VideoController();
			_controller.player = this;
			_controller.init();
			_view.addChild( _controller );
			
			stageUpdate( StageManager.largeur, StageManager.hauteur );
		}
		
		public function set controllerMode( cm:String ):void
		{
			_controllerMode = cm;
			
			if ( _controllerMode == ControllerMode.ON_ROLL ) {
				
				if ( !hasEventListener( MouseEvent.ROLL_OVER ) ){
					addEventListener( MouseEvent.ROLL_OVER, _onRollOver );
					addEventListener( MouseEvent.ROLL_OUT, _onRollOut );
				}
				
				_relocate();
			}
		}
		
		private function _relocate( w:int = 0, h:int = 0, t:int = 0 ):void
		{
			if ( _display == null || _controller == null ) return;
			
			_controller.x = 20;

			var posY:int = ( h != 0 ) ? h - 15 : _display.baseHeight - 15;
			
			Tweener.addTween( _controller, { y:posY, _autoAlpha:1, time:t } );
			
			if ( _bt_play_big == null ) return;
			
			_bt_play_big.x = ( w != 0 ) ? w / 2 : _display.baseWidth / 2;
			_bt_play_big.y = ( h != 0 ) ? h / 2 : _display.baseHeight / 2;
		}
		
		private function _delocate( w:int = 0, h:int = 0 ):void
		{
			if ( _display == null || _controller == null ) return;
			
			_controller.x = 20;

			var posY:int = ( h != 0 ) ? h : _display.baseHeight;
			
			Tweener.addTween( _controller, { y:posY, _autoAlpha:0, time:1 } );
		}
		
		// - - -
		
		private function _onRollOver( e:MouseEvent ):void 
		{
			_showControls();
		}
		
		private function _onRollOut( e:MouseEvent ):void
		{			
			_killTimer();
			
			_t = new Timer( 1500, 1 );
			_t.addEventListener( TimerEvent.TIMER_COMPLETE, _hideControls );
			_t.start();
		}
		
		
		
		private function _showControls():void
		{
			_killTimer();
			
			_relocate( 0, 0, 1 );
		}
		
		private function _hideControls( e:TimerEvent ):void
		{
			_delocate();
		}
		
		private function _killTimer():void
		{
			if ( _t != null ){
				_t.stop();
				_t.removeEventListener( TimerEvent.TIMER_COMPLETE, _hideControls );
				_t = null;
			}
		}
		
		///////  L I S T

		override public function addListItem( u:String, t:String = "", p:String = "" ):void
		{
			if ( _list == null ) _list = new AList( true );
			
			_list.addItem( new VideoListItem( u, t, p ) );
		}
		

		// - - -
		
		override public function previous():void
		{
			var item:AListItem = _list.getPreviousItem();
			
			_playMedia( item );
		}
		
		override public function next():void
		{
			var item:AListItem = _list.getNextItem();
			
			_playMedia( item );
		}
		
		///////  T R A C K
		
		override public function play( i:int = -1 ):void
		{
			if ( _list == null ) {
				//throw new Error( " VideoPlayer -- no VideoListItem added" );
				trace(" ");
				trace("VideoPlayer -- no VideoListItem added to the list");
				return;
			}
			
			if ( _connection == null )
			{
				trace("VideoPlayer : connect() should be called first");
				return;
			}
			
			var item:AListItem = ( i >= 0 ) ? _list.getItemByIndex( i ) : _list.getNextItem();
			
			_playMedia( item );
		}
		
		override public function stop():void
		{
			if ( _currentMedia != null ) _currentMedia.stop();
		}
		
		override public function pause():void
		{
			if ( _currentMedia != null ) _currentMedia.pause();
		}
		
		
		private function _playMedia( item:AListItem ):void
		{
			if ( item == null ) return;

			_killMedia();

			var parameters:VideoMediaParameters = new VideoMediaParameters();
			parameters.controller = _controller;

			_currentMedia = new VideoMedia( item.url, _connection.netStream, parameters );
			_currentMedia.addEventListener( MediaEvent.PLAY, _onPlay );
			_currentMedia.addEventListener( MediaEvent.STOP, _onStop );
			_currentMedia.play();
			
			if ( item.preview != "" && item.preview != _previewURL ) loadPreview( item.preview );
			
			_display.screen.visible = true;
			
			if ( !_autoPlay ) {
				_currentMedia.pause();
				if( _controller != null ) _controller.setPauseState();
				if( _bt_play_big != null ) _bt_play_big.visible = true;
				if ( _display.hasPreview ) _display.screen.visible = false;
				
			}  else {
				
				//SoundManager.instance.playSound( _currentMedia ); // old - test
			}

			_connection.netStream.client.addEventListener( InfoEvent.METADATA, _onMetaData );
		}
		
		private function _onPlay( e:MediaEvent ):void
		{
			if ( _bt_play_big != null ) _bt_play_big.visible = false;

			_display.screen.visible = true;
			
			//SoundManager.instance.playSound( _currentMedia ); // old - test
		}
		
		private function _onStop( e:MediaEvent ):void
		{
			if ( _bt_play_big != null ) _bt_play_big.visible = true;
			
			_display.screen.visible = false;
		}
		
		private function _onMetaData( e:InfoEvent ):void
		{
			var mediaRatio:Number = e.value.width / e.value.height;
			if ( _display != null ) _display.setScreenRatio( mediaRatio );
			if ( _controller != null && _controller.time_tool != null ) {
				_controller.time_tool.duration = e.value.duration;
			}
		}
		
		private function _killMedia():void
		{
			if ( _controller != null ) _controller.media = null;
			
			if ( _currentMedia != null ) {
				_currentMedia.removeEventListener( MediaEvent.PLAY, _onPlay );
				_currentMedia.removeEventListener( MediaEvent.STOP, _onStop );
				_currentMedia.dispose();
				_currentMedia = null;
			}
		}
		
		public function set loopMode( lm:String ):void
		{
			_loopMode = lm;
		}
		
		// ----- IStageObserver
		
		override public function stageUpdate( w:int, h:int ):void 
		{
			if ( _display != null ) _display.stageUpdate( w, h );

			switch ( StageManager.instance.getStage().displayState )
			{
				case StageDisplayState.FULL_SCREEN :
				
					if ( _controller != null ) _controller.stageUpdate( w, h );
					StageManager.instance.getStage().addChild( _view );
					_relocate( w, h );
					
					break;

				case StageDisplayState.NORMAL :
				
					if ( _controller != null && _display!= null ) _controller.stageUpdate( _display.baseWidth, _display.baseHeight );
					addChild( _view ); 
					_relocate();
					
					break;
			}
			
			super.stageUpdate( w, h );
		}
		
		// ----- IDisposable
		
		override public function dispose():void
		{
			_killMedia();
			
			if ( _display != null ) _display.dispose();
			if ( _controller != null ) _controller.dispose();
			if ( _connection != null ) _connection.dispose();
			
			super.dispose();
		}
		
	}

}